package vcsn;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Scanner;
import java.util.Set;
import java.util.Vector;

import javax.swing.JOptionPane;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.NoFilepatternException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;

import vcsn.Config.HeaderType;
import vcsn.Config.SyncStatus;
import vcsn.entities.LastAppliedCommitHashList;
import vcsn.entities.PeerList;
import vcsn.entities.VectorClock;
import vcsn.utils.ExportImportHandler;
import vcsn.utils.Util;

public class Configuration {
	
	private String projectPath; 
	private String projectName;
	private Git git;
	private Repository gitRepo;
	public Configuration(String projectPath, String projectName){
		this.projectPath = projectPath;
		this.projectName = projectName;
		try {
			git = Git.open(new File(projectPath));
			gitRepo = git.getRepository();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
//	public static String getAuthor(){
//		try{
//			File configFile = new File(System.getProperty(Config.homeDirectoryNotation) + File.separator  + Config.gitConfigFile);
//			if(!configFile.exists()){
//				return null;
//			}
//		
//			Scanner scn = new Scanner(configFile);
//			String author = null;
//			while(scn.hasNextLine()){
//				String result = scn.nextLine();
//				result = result.trim();
//				if(result.startsWith(Config.namePrefix)){
//					author = result.replace(Config.namePrefix, "");
//					break;
//				}
//			}
//			scn.close();
//			return author;
//		}catch (FileNotFoundException e) {
//			e.printStackTrace();
//			return null;
//		}catch (Exception ex){
//			ex.printStackTrace();
//			return null;
//		}
//	}
//	
//	public static String getEmail(){
//		File configFile = new File(System.getProperty(Config.homeDirectoryNotation) + File.separator  + Config.gitConfigFile);
//		if(!configFile.exists()){
//			return null;
//		}
//		try{
//			Scanner scn = new Scanner(configFile);
//			String author = null;
//			while(scn.hasNextLine()){
//				String result = scn.nextLine();
//				result = result.trim();
//				if(result.startsWith(Config.emailPrefix)){
//					author = result.replace(Config.emailPrefix, "");
//					break;
//				}
//			}
//			scn.close();
//			return author;
//		}catch (FileNotFoundException e) {
//			e.printStackTrace();
//			return null;
//		}
//	}
//	
	private StoredConfig getStoredConfig(){
		return gitRepo.getConfig();
	}
	
	private String getConfigSectionValue(String section, String subSection, String key){
		StoredConfig storedCfg = this.getStoredConfig();
		String returnValue = storedCfg.getString(section, subSection, key);
		return returnValue == null? "" : returnValue;
	}
	
	private void setConfigSectionValue(String section, String subSection, String key, String value){
		StoredConfig storedCfg = this.getStoredConfig();
		storedCfg.setString(section, subSection, key, value);
		try {
			storedCfg.save();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public boolean isMergeConfigExist(){
		if(!this.getConfigSectionValue(Config.branchSection, Config.masterSubSection, Config.remoteKey).isEmpty() &&
			!this.getConfigSectionValue(Config.branchSection, Config.masterSubSection, Config.mergeKey).isEmpty()){
			return true;
		}else{
			return false;
		}
	}

	public String getUserName(){
//		System.out.println(this.getConfigSectionValue(Config.userSection, null, Config.nameKey));
		return this.getConfigSectionValue(Config.userSection, null, Config.nameKey);
	}
	
	public String getUserEmail(){
//		System.out.println(this.getConfigSectionValue(Config.userSection, null, Config.emailKey));
		return this.getConfigSectionValue(Config.userSection, null, Config.emailKey);
	}
	
	public String getRemoteURI(){
//		System.out.println(this.getConfigSectionValue(Config.remoteSection, Config.originSubSection, Config.urlKey));
		return this.getConfigSectionValue(Config.remoteSection, Config.originSubSection, Config.urlKey);
	}
	
	public void setUserName(String value){
		this.setConfigSectionValue(Config.userSection, null, Config.nameKey, value);
	}
	
	public void setUserEmail(String value){
		this.setConfigSectionValue(Config.userSection, null, Config.emailKey, value);
	}
	
	public void setRemoteURI(String value){
		this.setConfigSectionValue(Config.remoteSection, Config.originSubSection, Config.urlKey, value);
		this.setConfigSectionValue(Config.remoteSection, Config.originSubSection, Config.fetchKey, "+refs/heads/*:refs/remotes/origin/*");
		
	}
	public void setMergeSection(){
		this.setConfigSectionValue(Config.branchSection, Config.masterSubSection, Config.remoteKey, "origin");
		this.setConfigSectionValue(Config.branchSection, Config.masterSubSection, Config.mergeKey, "refs/heads/master");
	}
		
	public Vector<String> getPeerList(){
		return new PeerList().getPeerList(projectPath + File.separator + Config.peerFile);
	}
	
	
	public boolean setPeerList(Vector<String> peerList){
		File peerFile = new File(projectPath + File.separator + Config.peerFile);

		try {

			PeerList peerhandler = new PeerList();
			File tmpPeerFile = Util.createTempFile();
			peerhandler.updateLocalPeerList(tmpPeerFile.getAbsolutePath(), peerList);
			
			VectorClock localClock = ExportImportHandler.importVectorClock(System.getProperty(Config.homeDirectoryNotation) + File.separator + Config.localClockFile, projectName);
			if(localClock != null){
				localClock.incrementClock(this.getUserName() + Config.keyConnector + this.getUserEmail());
			}else{
				localClock = new VectorClock();
				localClock.incrementClock(this.getUserName() + Config.keyConnector + this.getUserEmail());
			}
			ExportImportHandler.exportVectorClock(localClock, projectName);
			
//			Git git = Git.open(new File(projectPath));
			
			ClientThread client = new ClientThread();
			String localAddress = client.getLocalAddress(tmpPeerFile);
			if(localAddress.isEmpty() || localAddress == null){
				localAddress = client.getLocalAddress(peerFile);
			}
			
			if(peerList.size() == 1 && peerList.contains(localAddress)){
				// update peer file and commit
				peerhandler.updateLocalPeerList(peerFile.getAbsolutePath(), peerList);
				git.add().addFilepattern(Config.peerFile).call();
				git.commit().setAuthor(this.getUserName(), this.getUserEmail()).setMessage(Config.peerFileUpdateMsg).call();
				
				// update head hash
				LastAppliedCommitHashList hashList = ExportImportHandler.importLastAppliedCommitHashList(System.getProperty(Config.homeDirectoryNotation) + File.separator + Config.lastAppliedCommitHashListFile, projectName);
				hashList.setCommitHash(this.getUserName(), git.getRepository().getRef("HEAD").getObjectId().getName());
				ExportImportHandler.exportLastAppliedCommitHashList(hashList, projectName);
				
				// push to server
				git.push().setRemote(this.getRemoteURI()).setForce(true).call();
				Config.status = SyncStatus.ONLINE;
				JOptionPane.showMessageDialog(null, Config.syncStatusMsg + Config.status, Config.syncDialogTitle, JOptionPane.INFORMATION_MESSAGE);
			}else if(peerList.size() < 1){
				// update peer file and commit
				peerhandler.updateLocalPeerList(peerFile.getAbsolutePath(), peerList);
				git.add().addFilepattern(Config.peerFile).call();
				git.commit().setAuthor(this.getUserName(), this.getUserEmail()).setMessage(Config.peerFileUpdateMsg).call();
				
				// update head hash
				LastAppliedCommitHashList hashList = ExportImportHandler.importLastAppliedCommitHashList(System.getProperty(Config.homeDirectoryNotation) + File.separator + Config.lastAppliedCommitHashListFile, projectName);
				hashList.setCommitHash(this.getUserName(), git.getRepository().getRef("HEAD").getObjectId().getName());
				ExportImportHandler.exportLastAppliedCommitHashList(hashList, projectName);
				
				// push to server
				git.push().setRemote(this.getRemoteURI()).setForce(true).call();
				Config.status = SyncStatus.OFFLINE;
				JOptionPane.showMessageDialog(null, Config.syncStatusMsg + Config.status, Config.syncDialogTitle, JOptionPane.INFORMATION_MESSAGE);
			}else{
				client.writeHeaderIntoPackageFile(projectName, localClock, localAddress, HeaderType.PEER);
				client.writeFileIntoPackageFile(tmpPeerFile);
				client.flush(tmpPeerFile);
				client.disposePackage();
				Config.status = SyncStatus.SYNC;
			}
			tmpPeerFile.delete();
			return true;
		} catch (Exception ex){
			ex.printStackTrace();
			return false;
		}
	}
}
